﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Antlr;
using Antlr.Runtime;
using Antlr.Runtime.Tree;
using System.Collections;
using cudaTranslator;
using MathNet.Numerics.LinearAlgebra.Single;
using cudaMatrix;
using System.IO;

namespace CudaTranslator
{
    #region zmienne

    #region variable
    //klasa rodzic wszystkich zmiennych, posiada metody wirtualne
    class Variable
    {
        //typ i nazwa zmiennej
        private string type, name;

        //konstruktor klasy podstawowej
        public Variable(string _type,string _name) {
            type = _type;
            name=_name;
        }

        //getter dla nazwy zmiennej
        public string GetName() {
            return name;
        }

        //getter dla typu zmiennej
        public string GetVariableType() {
            return type;
        }

        //metoda wirtualna, zwraca wartość dla typu zmiennej
        public virtual Object GetValue(){
        return new Object();
        }

        //metoda wirtualna, ustawia wartość dla typu zmiennej
        public virtual void SetValue(Object _object)
        {}
    }

#endregion

    #region functionVariable
    //zmienna trzymajaca informacje o funkcji
    class Function : Variable {

        //referencja na drzewo zawierające instrukcje funkcji
        private CommonTree functionDeclaraction;

        //lista ze zmiennymi, któe zostaną użyte w funkcji
        private LinkedList<Variable> variableList=new LinkedList<Variable>();

        //konstruktor
        public Function(CommonTree _functionDeclaration, string _name) : base("function",_name) {
            functionDeclaraction = _functionDeclaration;
        }
        

        public CommonTree GetDeclaration() {
            return functionDeclaraction;
        }

        //zwraca wartość dla typu zmiennej
        public Object GetValue() {
            return functionDeclaraction;
        }

        //zwraca wartość dla typu zmiennej
        public LinkedList<Variable> GetList()
        {
            return variableList;
        }

        //zwraca wartość dla typu zmiennej
        public void SetList(LinkedList<Variable> list)
        {

            variableList = list;
        }

    }

    #endregion

    #region matrixVariable
    //zmienna trzymajaca informacje o macierzy
    class MatrixVariable : Variable {

        //macierz uzywana w zmiennej
        private DenseMatrix matrix;
        public MatrixVariable(string _name, DenseMatrix _matrix)
            : base("matrix", _name)
        {
            matrix = _matrix;  //-- macierz może być dowolnego typu
        }

        //zwraca wartość dla typu zmiennej
        public override Object GetValue()
        {
            return matrix;
        }

        //ustawia wartość dla typu zmiennej
        public override void SetValue(Object _object)
        {
                matrix = (DenseMatrix)_object;
        }

    }
    #endregion

    #region integerVariable
    //zmienna trzymajaca informacje o typie całkowitoliczbowym
    class IntegerVariable : Variable {

        //wartość przechowywana w klasie
        private int number;

        //konstruktor korzystający z konstruktora bazowego
        public IntegerVariable(string _name, int _number) : base("int",_name){
            number=_number;
        }

        //zwraca wartość dla typu zmiennej
        public override Object GetValue()
        {
            return number ;
        }

        //ustawia wartość dla typu zmiennej
        public override void SetValue(Object _object)
        {
            if (_object.GetType() == number.GetType())
            {
                number = (int)_object;
            }
            else
            {
                Console.WriteLine("Error 32 : Uncompatible types for int");
            }

        }

    }
    #endregion

    #region floatVariable
    //zmienna trzymajaca informacje o typie o pojedynczej precyzji
    class FloatVariable : Variable { 

        //wartość przechowywana w klasie
        private float number;

        //konstruktor używający konstruktora bazowego
        public FloatVariable(string _name, float _number) : base("float",_name){
            number=_number;
        }

        //zwraca wartość dla typu zmiennej

        public override Object GetValue()
        {
            return number;
        }

        //ustawia wartość dla typu zmiennej
        public override void SetValue(Object _object)
        {
            if (_object.GetType() == number.GetType())
            {
                number = (float)_object;
            }
            else {
                Console.WriteLine("Error 32 : Uncompatible types for float");
            }
        }
    }
    #endregion

    #region stringVariable
    //zmienna trzymajaca informacje o stringu
    class StringVariable : Variable { 

        //wartosc przechowywana w klasie
        private string text;

        //konstruktor używający konstruktora bazowego
        public StringVariable(string _name, string _text) : base("string",_name){
            text=_text;
        }

        //zwraca wartość dla typu zmiennej
        public override Object GetValue()
        {
            return text;
        }

        //ustawia wartość dla typu zmiennej
        public override void SetValue(Object _object)
        {
            if (_object.GetType() == text.GetType())
            {
                text = (string)_object;
            }
            else
            {
                Console.WriteLine("Error 32 : Uncompatible types for string");
            }

        }
    }

    #endregion

    #endregion

    #region treeWalker
    //klasa służaca to analizy wygenerowanego drzewa
    public class TreeWalker
    {
        //słownik zmiennych globalnych
        private Dictionary<string, Variable> variablesGlobal = new Dictionary<string, Variable>();   

        //lista scopów- każdy scope jest słownikiem, do zmiennych zaczyna się dostawać od ostatniego
        private LinkedList<Dictionary<string,Variable>> variableScopes=  new LinkedList<Dictionary<string,Variable>>();
        
        //referencja do parsera w celu uzyskania nazw tokenów
        private CudaTranslatorParser parser;

        //stream na ktory pisze wyjscie
        TextWriter Console;        

        //konstruktor
        public TreeWalker(CudaTranslatorParser _parser, TextWriter stream)
        {
            //stream na ktory pisze wyjscie
            Console = stream;

            //doajemy scope globalny
            variableScopes.AddFirst(variablesGlobal);

            //referencja do parsera
            parser=_parser;

            //dodajemy funkcje ogólne do zasięgu globalnego
            foreach (var v in MatrixFactory.getAllowedOperations().Keys)
            {
                variablesGlobal.Add(v, new Function(null, v));

            }
            foreach (var v in MatrixFactory.getAllowedOperationsOneParam().Keys)
            {
                variablesGlobal.Add(v, new Function(null, v));

            }
        }

        //główny program analizujący, moze zostac wywolany rekurencyjnie 
        public Object WalkAndAnalyse(CommonTree currentTree){

            Object returnObject = null;
           // Console.WriteLine("\n\n"+currentTree.ToStringTree());

            //sprawdza czy drzewo nie jest puste
            int childrenCount = currentTree.ChildCount;
            if(childrenCount==0){
                return null;
            }

            foreach (CommonTree tr in currentTree.Children)
           {
               //dla deklaracji TYPE jest korzeniem
               if (parser.TokenNames[tr.Type] == "TYPE") {
                   GetDeclarations(tr);
               }

               //dla funkcji ID jest korzeniem
               else if (parser.TokenNames[tr.Type] == "ID")
               {
                   GetFunction(tr);
               }
                
               //pozostałe statements- czyli return, print i reszta...
               else {
                   returnObject=ParseChild(tr);
                   if (returnObject != null) {
                       return returnObject;
                   }
               }
           }
            //wartość zwracana - w przypadku funkcji użyteczne, innaczej null
            return returnObject;
        }

       //parsuje deklaracje zmiennych
       public void GetDeclarations(CommonTree tree){

           //id ostaniej zmiennej
           string lastID = "";
           foreach (CommonTree tr in tree.Children)
           {
               //dopisujemy wartosc
               if (tr.Text == "=") {
                   Variable sought = FindLastVariable(lastID);
                   EvaluateExpression((CommonTree)tr,sought);
               }
               if (parser.TokenNames[tr.Type] == "ID")
               {
                   //jeżeli zmienna już istnieje w tym scopie
                   if(variableScopes.Last().Keys.Contains(tr.Text)){
                       Console.WriteLine("Eror 37: variable"+tr.Text + " already exists!");
                       throw new ApplicationException();
                   }
                   //sprawdzmy czy int
                   if ( tr.Parent.Text == "int") {
                       lastID = tr.Text;                       
                       variableScopes.Last().Add(tr.Text, new IntegerVariable(tr.Text, 0));
                   }

                   //sprawdzamy czy matrix
                   if ( tr.Parent.Text == "matrix")
                   {
                       lastID = tr.Text;
                       float[] tmpmat =  {0};
                       variableScopes.Last().Add(tr.Text, new MatrixVariable(tr.Text, MatrixFactory.createMatrix(1,1,tmpmat)));
                   }

                   //sprawdzamy czy float
                   if ( tr.Parent.Text == "float")
                   {
                       lastID = tr.Text;
                       variableScopes.Last().Add(tr.Text, new FloatVariable(tr.Text, 0.0f));//jesli nastepny to '='
                   }

                   //sprawdzamy czy string
                   if ( tr.Parent.Text == "string")
                   {
                       lastID = tr.Text;
                       variableScopes.Last().Add(tr.Text, new StringVariable(tr.Text, ""));
                   }
               }

               
           }
       }

       //dodawanie funkcji
       public void GetFunction(CommonTree tree)//wskaznik do poczatku funkcji
       {
           //tworzymy nową zmienną funkcji
           Function f=new Function((CommonTree)tree.Children[tree.ChildCount-1], tree.Text);

           //parsujemy zmienne
           LinkedList<Variable> variableList = new LinkedList<Variable>();
           int ichild=0;
           foreach (CommonTree tr in tree.Children)
           {
               //sprawdzamy zmienne id 1 (bez typu funkcji)
               if (parser.TokenNames[tr.Type] == "TYPE" && ichild!=0)
               {
                   //sprawdzmy czy int
                   if (tr.Text == "int")
                   {
                       variableList.AddLast(new IntegerVariable(tree.Children[ichild+1].Text, 0));
                   }

                   //sprawdzamy czy matrix
                   if (tr.Text == "matrix")
                   {
                       float[] tmpmat = { 0 };
                       variableList.AddLast(new MatrixVariable(tree.Children[ichild + 1].Text, MatrixFactory.createMatrix(1, 1, tmpmat)));
                   }

                   //sprawdzamy czy float
                   if (tr.Text == "float")
                   {
                       variableList.AddLast(new FloatVariable(tree.Children[ichild + 1].Text, 0.0f));
                   }

                   //sprawdzamy czy string
                   if (tr.Text == "string")
                   {
                       variableList.AddLast(new StringVariable(tree.Children[ichild + 1].Text, ""));
                   }
               }

               ichild++;
           }

           //dodajemy zmienną funkcji
           f.SetList(variableList);
           variableScopes.Last().Add(tree.Text, f);
              
       }

        //pozostałe możliwe polecenia
        public Object ParseChild(CommonTree tree)//wskaznik do odpowiednich czesci kodu
        {
            //ustawiamy obiekt zwracany początkowo na null
            Object returnObject = null;

            #region print
            if (tree.Text == "print") { 

                //jeśli macierz to trzeba podmienić , na . i ; na , by było zgodne z naszą notacją
                Object o = Eval((CommonTree)tree.Children[0]);
                float[] tmpmat =  {0};
                DenseMatrix i = MatrixFactory.createMatrix(1, 1, tmpmat);
                if (o.GetType() == i.GetType()) {
                    Console.WriteLine((((string)o.ToString()).Replace(",",".")).Replace(";",","));
                }
                else Console.WriteLine(o);
            }
            #endregion

            #region simple_statement
            else if (tree.Text == ";")
            {
                
                //szukamy zmiennej
                Variable sought = FindLastVariable(tree.Children[0].Text);
                Function func;
                //wywoływanie funkcji 
                if (sought.GetVariableType() == "function" && sought!=null)
                {
                    //nowy scope
                    variableScopes.AddLast(new Dictionary<string, Variable>());
                    func=(Function)sought;

                    //dodaje wartosci do zmiennych i dodanie zmiennych do scopu
                    int y = 1;
                    foreach (Variable v in func.GetList()) {
                        variableScopes.Last().Add(v.GetName(), v);
                        v.SetValue(Eval((CommonTree)tree.Children[y]));
                        y++;
                    } 
                    //jeżeli jest to z góry zdefiniowana funkcja
                    if (MatrixFactory.getAllowedOperations().Keys.Contains(tree.Text))
                    {
                        var functionName = MatrixFactory.getAllowedOperations()[tree.Text];
                        functionName(int.Parse(tree.Children[0].Text), int.Parse(tree.Children[1].Text));
                    }
                    else if (MatrixFactory.getAllowedOperationsOneParam().Keys.Contains(tree.Text))
                    {
                        var functionName = MatrixFactory.getAllowedOperationsOneParam()[tree.Text];
                        functionName(Eval(tree));
                    }
                    else WalkAndAnalyse(func.GetDeclaration());
                    variableScopes.RemoveLast();
                }

                //nadpisywanie elmentów macierzy
                else if (sought.GetVariableType() == "matrix" && tree.ChildCount >= 4) {
                    
                    float value=(float)Eval((CommonTree)((CommonTree)tree.Children[3]).Children[0]);
                    ((DenseMatrix)sought.GetValue()).At(int.Parse(tree.Children[1].Text), int.Parse(tree.Children[2].Text), value);
                }
                //w przypadku złej liczby argumentów
                else if (sought.GetVariableType() == "matrix" && tree.ChildCount == 3)
                {
                    Console.WriteLine("Error reading Matrix");    
                }
                //w przeciwnym wypadku zwykly ID
                else EvaluateExpression((CommonTree)tree.Children[1], sought);

            }
            #endregion

            #region {}
            //nawiasy wąsate
            else if (tree.Text == "{")
            {
                //dodaje nowy zasięg
                variableScopes.AddLast(new Dictionary<string, Variable>());
                returnObject = WalkAndAnalyse(tree);
                //usuwa zasięg
                variableScopes.RemoveLast();
                if (returnObject != null) return returnObject;
            }
            #endregion

            #region funcstmt
            //funkcja - zasięg tworzony wcześniej
            else if (tree.Text == "}")
            {
                returnObject = WalkAndAnalyse(tree);
                //jeżeli jest return statement- można też ućyć jako break
                if (returnObject != null) return returnObject;
            }
            #endregion

            #region return
            //zwraca wartosc obliczona lub działa jako break
            else if (tree.Text == "return")
            {

                if (tree.ChildCount == 2)
                {
                    returnObject = Eval((CommonTree)tree.Children[0]);
                }
                else returnObject = new Object();
                return returnObject;
            }
            #endregion

            #region if
            //if - statement
            else if (tree.Text == "if")
            {
                if ((int)Eval((CommonTree)tree.Children[0])!=0) {
                    WalkAndAnalyse((CommonTree)tree.Children[1]);
                }
                else {
                    if (tree.ChildCount > 2) {
                        WalkAndAnalyse((CommonTree)tree.Children[3]);
                    }
                }
            }
            #endregion

            #region while
            //while statement
            else if (tree.Text == "while")
            {
                while ((int)Eval((CommonTree)tree.Children[0]) != 0)
                {
                    WalkAndAnalyse((CommonTree)tree.Children[1]);
                }
                
            }
            #endregion

            #region for
            else if (tree.Text == "for")
            {
                //pierwszy INTCON
                int j=1;
                int neg = 1;

                //patrzymy czy jest negacja
                if (parser.TokenNames[tree.Children[j].Type] == "NEGATION") { neg = -1; j++; }
                //Console.WriteLine(neg+" j = "+j);

                //wpisujemy zmienną
                Variable sought = FindLastVariable(tree.Children[0].Text);

                //ewaluujemy zmienna
                int foundValue=-12;
                if (sought != null)
                {
                    foundValue=(int)Eval((CommonTree)tree.Children[j]);

                    sought.SetValue(foundValue);
                }
                int i=neg*foundValue;

                //drugi INTCON
                j++;
                neg = 1;
                if (parser.TokenNames[tree.Children[j].Type] == "NEGATION") { neg = -1; j++; }
                int n = neg * (int)Eval((CommonTree)tree.Children[j]);
                
                //właściwy for
                for (; i <= n;i++ )
                {
                    WalkAndAnalyse((CommonTree)tree.Children[j + 1]);
                    //zmieniamy wartosc zmiennej
                    sought.SetValue(i);
                }

            }
            #endregion

            //zwraca null lub konkretną wartość
            return returnObject;
        }

        //szuka czy istnieje dana zmienna
        private Variable FindLastVariable(string id) {
            Variable tmp=null;
            foreach (Dictionary<string, Variable> d in variableScopes)
            {
                if (d.ContainsKey(id)) { tmp = d[id];
                }
            }
            if (tmp == null) {
                Console.WriteLine("No such variable: " + id);
                throw new ApplicationException();
            }

                return tmp;
        }

        //wywoływanie szacowania wartości
        private void EvaluateExpression(CommonTree tree,Variable sought)
        {
            
            if (sought != null)
            {
                sought.SetValue(Eval((CommonTree)tree.Children[0]));
            }
        }

        //szacowanie wartości - wywołanie właściwej operacji
        private Object Eval(CommonTree tree) {
            if (parser.TokenNames[tree.Type] == "ID")
            {
                Variable sought = FindLastVariable(tree.Text);
                //Console.WriteLine(sought.GetName());
                if (sought.GetVariableType() == "function" && sought!=null) {
                    //nowy zasięg
                    
                    variableScopes.AddLast(new Dictionary<string, Variable>());
                    Function func = (Function)sought;
                    
                    //dodaje wartosci do zmiennych i dodanie zmiennych do zasięgu
                    int y = 0;
                    foreach (Variable v in func.GetList())
                    {
                        variableScopes.Last().Add(v.GetName(), v);
                        v.SetValue(Eval((CommonTree)tree.Children[y]));
                        y++;
                    }
                    //ewentualny obiekt do zwracania
                    Object o = null;
                    //jeżeli jest to z góry zdefiniowana funkcja
                    if (MatrixFactory.getAllowedOperations().Keys.Contains(tree.Text))
                    {
                        var zeros = MatrixFactory.getAllowedOperations()[tree.Text];
                        o = (DenseMatrix)zeros(Eval((CommonTree)tree.Children[0]), Eval((CommonTree)tree.Children[1]));
                    }
                    else if (MatrixFactory.getAllowedOperationsOneParam().Keys.Contains(tree.Text))
                    {
                        var zeros = MatrixFactory.getAllowedOperationsOneParam()[tree.Text];
                        o = (float)zeros(Eval((CommonTree)tree.Children[0]));
                    }
                    else o = WalkAndAnalyse(func.GetDeclaration());
                    //usuwamy zasięg
                    variableScopes.RemoveLast();
                    //zwracamy wartość
                    return o;
                }
                //pobieranie elmentów macierzy
                else if (sought.GetVariableType() == "matrix" && tree.ChildCount ==2)
                {
                    return (float)((DenseMatrix)sought.GetValue()).At(int.Parse(tree.Children[0].Text), int.Parse(tree.Children[0].Text));
                }
                else return FindLastVariable(tree.Text).GetValue();
            }
                //wszytkie pozostałe akcje możliwe wywołane rekurencyjnie
            else if (parser.TokenNames[tree.Type] == "INTCON")
                return Convert.ToInt32(tree.Text);
            else if (parser.TokenNames[tree.Type] == "STRINGCON")
                return tree.Text.Replace("\"", "");
            else if (parser.TokenNames[tree.Type] == "FLOATCON")
            {
                string tmp = tree.Text;
                return Single.Parse(tmp.Replace(".", ","));
            }
            else if (tree.Text == "[")
                return ParseMatrix(tree);
            else if (tree.Text == "+")
                return SumEval(Eval((CommonTree)tree.Children[0]), Eval((CommonTree)tree.Children[1]));
            else if (tree.Text == "-")
                return MinusEval(Eval((CommonTree)tree.Children[0]), Eval((CommonTree)tree.Children[1]));
            else if (tree.Text == "*")
                return MultEval(Eval((CommonTree)tree.Children[0]), Eval((CommonTree)tree.Children[1]));
            else if (tree.Text == "/")
                return DivEval(Eval((CommonTree)tree.Children[0]), Eval((CommonTree)tree.Children[1]));
            else if (tree.Text == ".*")
                return MultDotEval(Eval((CommonTree)tree.Children[0]), Eval((CommonTree)tree.Children[1]));
            else if (tree.Text == "./")
                return DivDotEval(Eval((CommonTree)tree.Children[0]), Eval((CommonTree)tree.Children[1]));
            else if (parser.TokenNames[tree.Type] == "NEGATION")
                return NegationEval(Eval((CommonTree)tree.Children[0]));
            else if (tree.Text == "&&")
                return ANDEval(Eval((CommonTree)tree.Children[0]), Eval((CommonTree)tree.Children[1]));
            else if (tree.Text == "||")
                return OREval(Eval((CommonTree)tree.Children[0]), Eval((CommonTree)tree.Children[1]));
            else if (tree.Text == "^^")
                return XOREval(Eval((CommonTree)tree.Children[0]), Eval((CommonTree)tree.Children[1]));
            else if (tree.Text == "!")
                return NOTEval(Eval((CommonTree)tree.Children[0]));
            else if (tree.Text == "==")
                return EqualEval(Eval((CommonTree)tree.Children[0]), Eval((CommonTree)tree.Children[1]));
            else if (tree.Text == "!=")
                return NotEqualEval(Eval((CommonTree)tree.Children[0]), Eval((CommonTree)tree.Children[1]));
            else if (tree.Text == ">=")
                return GreaterOrEqualEval(Eval((CommonTree)tree.Children[0]), Eval((CommonTree)tree.Children[1]));
            else if (tree.Text == ">")
                return GreaterEval(Eval((CommonTree)tree.Children[0]), Eval((CommonTree)tree.Children[1]));
            else if (tree.Text == "<=")
                return LessOrEqualEval(Eval((CommonTree)tree.Children[0]), Eval((CommonTree)tree.Children[1]));
            else if (tree.Text == "<")
                return LessEval(Eval((CommonTree)tree.Children[0]), Eval((CommonTree)tree.Children[1]));
            else if (tree.Text == "'")
                return InverseEval(Eval((CommonTree)tree.Children[0]));
            else {
                Console.WriteLine("Error : 3032 - unknown operator");
                return 661;
            } // jescze jakiś błąd
        }

        private Object SumEval(Object o1,Object o2) {
            //pomocnicze zmienne do typow
            int i = 0;
            float f = 0.0f;
            string s = "";
            float[] tmpmat = { 0 };
            DenseMatrix m = MatrixFactory.createMatrix(1, 1, tmpmat);
            //koniec

            if (o1.GetType() == i.GetType() && o2.GetType() == i.GetType())
                return (int)o1 + (int)o2;
            else if (o1.GetType() == f.GetType() && o2.GetType() == f.GetType())
                return (float)o1 + (float)o2;
            else if (o1.GetType() == s.GetType() && o2.GetType() == s.GetType())
                return (string)o1 + (string)o2;
            else if (o1.GetType() == m.GetType() && o2.GetType() == m.GetType())
                return (DenseMatrix)o1 + (DenseMatrix)o2;             
            return 0;
        }

        private Object MinusEval(Object o1, Object o2)
        {
            //pomocnicze zmienne do typow
            int i = 0;
            float f = 0.0f;
            string s = "";
            float[] tmpmat = { 0 };
            DenseMatrix m = MatrixFactory.createMatrix(1, 1, tmpmat);
            //koniec

            if (o1.GetType() == i.GetType() && o2.GetType() == i.GetType())
                return (int)o1 - (int)o2;
            else if (o1.GetType() == f.GetType() && o2.GetType() == f.GetType())
                return (float)o1 - (float)o2;
            else if (o1.GetType() == s.GetType() && o2.GetType() == s.GetType())
            {
                Console.WriteLine("Error : Operation '-' not specified for string");
            }
            else if (o1.GetType() == m.GetType() && o2.GetType() == m.GetType())
                return (DenseMatrix)o1 - (DenseMatrix)o2;
            return 0;
        }

        private Object MultEval(Object o1, Object o2)
        {
            //pomocnicze zmienne do typow
            int i = 0;
            float f = 0.0f;
            string s = "";
            float[] tmpmat = { 0 };
            DenseMatrix m = MatrixFactory.createMatrix(1, 1, tmpmat);
            //koniec

            if (o1.GetType() == i.GetType() && o2.GetType() == i.GetType())
                return (int)o1 * (int)o2;
            else if (o1.GetType() == f.GetType() && o2.GetType() == f.GetType())
                return (float)o1 * (float)o2;
            else if (o1.GetType() == s.GetType() && o2.GetType() == s.GetType())
            {
                Console.WriteLine("Error : Operation '*' not specified for string");
            }
            else if (o1.GetType() == m.GetType() && o2.GetType() == m.GetType())
                return (DenseMatrix)o1 * (DenseMatrix)o2;
            return 0;
        }

        private Object DivEval(Object o1, Object o2)
        {
            //pomocnicze zmienne do typow
            int i = 0;
            float f = 0.0f;
            string s = "";
            float[] tmpmat = { 0 };
            DenseMatrix m = MatrixFactory.createMatrix(1, 1, tmpmat);
            //koniec

            if (o1.GetType() == i.GetType() && o2.GetType() == i.GetType())
                return (int)o1 / (int)o2;
            else if (o1.GetType() == f.GetType() && o2.GetType() == f.GetType())
                return (float)o1 / (float)o2;
            else if (o1.GetType() == s.GetType() && o2.GetType() == s.GetType())
            {
                Console.WriteLine("Error : Operation '/' not specified for string");
            }
            else if (o1.GetType() == m.GetType() && o2.GetType() == m.GetType())
                return (DenseMatrix)o1 * ((DenseMatrix)o2).Inverse();
            return 0;
        }

        private Object MultDotEval(Object o1, Object o2)
        {
            //pomocnicze zmienne do typow
            int i = 0;
            float f = 0.0f;
            string s = "";
            float[] tmpmat = { 0 };
            DenseMatrix m = MatrixFactory.createMatrix(1, 1, tmpmat);
            //koniec

            if (o1.GetType() == i.GetType() && o2.GetType() == i.GetType())
                return (int)o1 * (int)o2;
            else if (o1.GetType() == f.GetType() && o2.GetType() == f.GetType())
                return (float)o1 * (float)o2;
            else if (o1.GetType() == s.GetType() && o2.GetType() == s.GetType())
            {
                Console.WriteLine("Error : Operation '-' not specified for string");
            }
            else if (o1.GetType() == m.GetType() && o2.GetType() == m.GetType())
                return MatrixFactory.ValueWiseMultiply((DenseMatrix)o1,(DenseMatrix)o2);
            return 0;
        }

        private Object DivDotEval(Object o1, Object o2)
        {
            //pomocnicze zmienne do typow
            int i = 0;
            float f = 0.0f;
            string s = "";
            float[] tmpmat = { 0 };
            DenseMatrix m = MatrixFactory.createMatrix(1, 1, tmpmat);
            //koniec

            if (o1.GetType() == i.GetType() && o2.GetType() == i.GetType())
                return (int)o1 / (int)o2;
            else if (o1.GetType() == f.GetType() && o2.GetType() == f.GetType())
                return (float)o1 / (float)o2;
            else if (o1.GetType() == s.GetType() && o2.GetType() == s.GetType())
            {
                Console.WriteLine("Error : Operation '-' not specified for string");
            }
            else if (o1.GetType() == m.GetType() && o2.GetType() == m.GetType())
                return MatrixFactory.ValueWiseDivide((DenseMatrix)o1, (DenseMatrix)o2);
            return 0;
        }

        private Object NegationEval(Object o1)
        {
            //pomocnicze zmienne do typow
            int i = 0;
            float f = 0.0f;
            string s = "";
            float[] tmpmat = { 0 };
            DenseMatrix m = MatrixFactory.createMatrix(1, 1, tmpmat);
            //koniec

            if (o1.GetType() == i.GetType())
                return -(int)o1;
            else if (o1.GetType() == f.GetType() )
                return -(float)o1 ;
            else if (o1.GetType() == s.GetType() )
            {
                Console.WriteLine("Error : Operation '-' not specified for string");
            }
            else if (o1.GetType() == m.GetType() )
                return - (DenseMatrix)o1;
            return 0;
        }

        private Object ANDEval(Object o1, Object o2)
        {
            //pomocnicze zmienne do typow
            int i = 0;
            if (o1.GetType() == i.GetType() && o2.GetType() == i.GetType()){
                 if((int)o1!=0 && (int)o2!=0) return 1;
            }
            else 
                Console.WriteLine("Error : Operation '&&' not specified for string");
            return 0;
        }

        private Object OREval(Object o1, Object o2)
        {
            //pomocnicze zmienne do typow
            int i = 0;
            if (o1.GetType() == i.GetType() && o2.GetType() == i.GetType())
            {
                if ((int)o1 != 0 || (int)o2 != 0) return 1;
            }
            else
                Console.WriteLine("Error : Operation '&&' not specified for string");
            return 0;
        }

        private Object XOREval(Object o1, Object o2)
        {
            //pomocnicze zmienne do typow
            int i = 0;
            if (o1.GetType() == i.GetType() && o2.GetType() == i.GetType())
            {
                if (((int)o1 == 0 && (int)o2 != 0) || ((int)o1 != 0 && (int)o2 == 0)) return 1;
            }
            else
                Console.WriteLine("Error : Operation '&&' not specified for string");
            return 0;
        }

        private Object NOTEval(Object o1)
        {
            //pomocnicze zmienne do typow
            int i = 0;
            if (o1.GetType() == i.GetType() )
            {
                if ((int)o1 == 0) return 1;
                else return 0;
            }
            else
                Console.WriteLine("Error : Operation '&&' not specified for string");
            return 0;
        }

        private Object EqualEval(Object o1, Object o2)
        {
            //pomocnicze zmienne do typow
            int i = 0;
            float f = 0.0f;
            string s = "";
            float[] tmpmat = { 0 };
            DenseMatrix m = MatrixFactory.createMatrix(1, 1, tmpmat);
            //koniec
            if (o1.GetType() == i.GetType() && o2.GetType() == i.GetType())
                { if ((int)o1 == (int)o2) return 1; }
            else if (o1.GetType() == f.GetType() && o2.GetType() == f.GetType())
                {if ((float)o1 == (float)o2) return 1;}
            else if (o1.GetType() == s.GetType() && o2.GetType() == s.GetType())
                { if ((string)o1 == (string)o2) return 1; }
            else if (o1.GetType() == m.GetType() && o2.GetType() == m.GetType())
                { if ((DenseMatrix)o1 == ((DenseMatrix)o2)) return 1; }
            return 0;
        }

        private Object NotEqualEval(Object o1, Object o2)
        {
            //pomocnicze zmienne do typow
            int i = 0;
            float f = 0.0f;
            string s = "";
            float[] tmpmat = { 0 };
            DenseMatrix m = MatrixFactory.createMatrix(1, 1, tmpmat);
            //koniec
            if (o1.GetType() == i.GetType() && o2.GetType() == i.GetType())
            { if ((int)o1 != (int)o2) return 1; }
            else if (o1.GetType() == f.GetType() && o2.GetType() == f.GetType())
            { if ((float)o1 != (float)o2) return 1; }
            else if (o1.GetType() != s.GetType() && o2.GetType() == s.GetType())
            { if ((string)o1 != (string)o2) return 1; }
            else if (o1.GetType() != m.GetType() && o2.GetType() == m.GetType())
            { if ((DenseMatrix)o1 != ((DenseMatrix)o2)) return 1; }
            return 0;
        }

        private Object GreaterOrEqualEval(Object o1, Object o2)
        {
            //pomocnicze zmienne do typow
            int i = 0;
            float f = 0.0f;
            //koniec
            if (o1.GetType() == i.GetType() && o2.GetType() == i.GetType())
            { if ((int)o1 >= (int)o2) return 1; }
            else if (o1.GetType() == f.GetType() && o2.GetType() == f.GetType())
            { if ((float)o1 >= (float)o2) return 1; }
            else Console.WriteLine("Error : Operation '&&' not specified for string");
            return 0;
        }

        private Object GreaterEval(Object o1, Object o2)
        {
            //pomocnicze zmienne do typow
            int i = 0;
            float f = 0.0f;
            //koniec
            if (o1.GetType() == i.GetType() && o2.GetType() == i.GetType())
            { if ((int)o1 > (int)o2) return 1; }
            else if (o1.GetType() == f.GetType() && o2.GetType() == f.GetType())
            { if ((float)o1 > (float)o2) return 1; }
            else Console.WriteLine("Error : Operation '&&' not specified for string");
            return 0;
        }
      
        private Object LessOrEqualEval(Object o1, Object o2)
        {
            //pomocnicze zmienne do typow
            int i = 0;
            float f = 0.0f;
            //koniec
            if (o1.GetType() == i.GetType() && o2.GetType() == i.GetType())
            { if ((int)o1 <= (int)o2) return 1; }
            else if (o1.GetType() == f.GetType() && o2.GetType() == f.GetType())
            { if ((float)o1 <= (float)o2) return 1; }
            else Console.WriteLine("Error : Operation '&&' not specified for string");
            return 0;
        }

        private Object LessEval(Object o1, Object o2)
        {
            //pomocnicze zmienne do typow
            int i = 0;
            float f = 0.0f;
            //koniec
            if (o1.GetType() == i.GetType() && o2.GetType() == i.GetType())
            { if ((int)o1 < (int)o2) return 1; }
            else if (o1.GetType() == f.GetType() && o2.GetType() == f.GetType())
            { if ((float)o1 < (float)o2) return 1; }
            else Console.WriteLine("Error : Operation '&&' not specified for string");
            return 0;
        }

        private Object InverseEval(Object o1)
        {
            //pomocnicze zmienne do typow
            float[] tmpmat = { 0 };
            DenseMatrix m = MatrixFactory.createMatrix(1, 1, tmpmat);
            //koniec

            if (o1.GetType() == m.GetType())
                return ((DenseMatrix)o1).Inverse();
            else 
            {
                Console.WriteLine("Error : Operation is not specified");
            }
            
            return 0;
        }

        //parsowanie macierzy
        private Object ParseMatrix(CommonTree tree) {
            //parsujemy macierz
            int i = 0, j = 0;
            bool hasRange = false;
            bool isMinus = false;
            //na razie wszystkie tablice są float
            LinkedList<float> tmpList = new LinkedList<float>();
            foreach (CommonTree t in tree.Children)
                {
                    if (parser.TokenNames[t.Type] == "INTCON")
                    {
                        if (isMinus) { 
                            tmpList.AddLast(-(float)int.Parse(t.Text));
                            isMinus = false;
                        }
                        else tmpList.AddLast((float)int.Parse(t.Text));
                    }
                    else if (parser.TokenNames[t.Type] == "FLOATCON")
                    {
                        string tmp = t.Text;
                        if (isMinus)
                        {
                            tmpList.AddLast(-Single.Parse(tmp.Replace(".", ",")));
                            isMinus = false;
                        }
                        else tmpList.AddLast(Single.Parse(tmp.Replace(".", ",")));
                    }
                    else if (t.Text == "->") hasRange = true;
                    else if (parser.TokenNames[t.Type] == "NEGATION") isMinus = true;
                    else if (t.Text == ",") j++;
                    else if (t.Text == ";") { i++; j++; }
                    else { j++; i++; }
                }

            //jeżeli macierz jest w formie range
            int h = 0;
            if (hasRange) {
                float first = tmpList.ElementAt(0);
                float last = tmpList.ElementAt(1);
                tmpList.Clear();
                
                while (first < last+1) {
                    tmpList.AddLast(first);
                    first = first + 1;
                    h++;
                }
                return MatrixFactory.createMatrix(1, h, tmpList.ToArray());
            } 

            // zamiana na format akceptowany przez Math.Net
            float[] change = tmpList.ToArray();
            tmpList.Clear();
            j=j/i;
            for (int p = 0; p < j; p++) {
                for (int u = 0; u < i; u++) {
                    tmpList.AddLast(change[u * j + p]);
                }
            }
            return MatrixFactory.createMatrix(i, j, tmpList.ToArray());
        }
    }

        
    

    
#endregion
}